package com.cssw.fyzb.busi.api.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cssw.fyzb.busi.config.TpsClient;
import com.cssw.fyzb.busi.model.tps.Tf56PayQuickPayDataVo;
import com.cssw.fyzb.busi.model.tps.Tf56PayQuickPayVo;
import com.cssw.fyzb.busi.service.acct.AcctService;
import com.cssw.fyzb.busi.service.pay.PayService;
import com.cssw.fyzb.busi.service.pay.QuickPayService;
import com.cssw.fyzb.busi.service.system.SysParamService;
import com.cssw.fyzb.busi.service.user.UserService;
import com.cssw.fyzb.busi.util.BizUtil;
import com.cssw.fyzb.busi.util.Const;
import com.cssw.fyzb.busi.util.NumberUtil;
import com.cssw.fyzb.core.dao.system.SysParamDao;
import com.cssw.fyzb.core.exception.BizException;
import com.cssw.fyzb.core.model.dodb.*;
import com.cssw.fyzb.core.model.dodb.base.BaseUser;
import com.cssw.fyzb.core.model.vo.pay.QuickPayVo;
import com.cssw.fyzb.core.util.StringUtil;
import com.cssw.fyzb.core.util.TimeUtil;
import com.ijpay.core.kit.PayKit;
import com.ydn.appserver.Action;
import com.ydn.appserver.Request;
import com.ydn.appserver.Response;
import com.ydn.appserver.annotations.Function;
import com.ydn.appserver.annotations.Parameter;
import com.ydn.appserver.annotations.Type;
import com.ydn.simplecache.SimpleCache;
import com.ydn.simplelock.SimpleLock;
import com.ydn.simplelock.SimpleLockFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: yangyiqun
 * @Date: 2020/7/14 22:10
 */

@Function(description = "快捷签约信息", parameters = {
        @Parameter(name = "userId", type = Type.String, description = "用户标识", required = true),
        @Parameter(name = "busiType", type = Type.String, description = "业务类型(BT114-实名 BT200-福币购买 BT520-果子购买 BT530-开通vip)", required = true),
        @Parameter(name = "extendData", type = Type.String, description = "json格式扩展数据(原业务json串)", required = false),
        @Parameter(name = "quickId", type = Type.String, description = "快捷标识", required = true)
})
@Component
public class QuickPay implements Action {

    private static final Logger logger = LoggerFactory.getLogger(QuickPay.class);

    @Autowired
    private TpsClient tpsClient;

    @Autowired
    private QuickPayService quickPayService;

    @Autowired
    private UserService userService;

    @Autowired
    private SimpleCache simpleCache;

    @Autowired
    private PayService payService;

    @Autowired
    private SysParamService sysParamService;

    @Autowired
    private SimpleLockFactory simpleLockFactory;

    @Autowired
    private AcctService acctService;

    @Autowired
    private SysParamDao sysParamDao;

    //新老用户注册时间规则
    @Value("${task.limitDate:2021-01-21 00:00:00}")
    private String limitDateStr;

    @Override
    public Response execute(Request request) throws Exception {
        String busiType = request.getString("busiType");
        try {
            switch (busiType) {
                case BusiType.REAL_NAME_PAY:
                    return processReal(request, busiType);
                case BusiType.BUY_F_COIN:
                    return processBuyFCoin(request, busiType);
                case BusiType.BUY_GZ_COIN:
                    return processBuyGzCoin(request, busiType);
                case BusiType.OPEN_VIP:
                    return processOpenVip(request, busiType);
                default:
                    BizUtil.exception("不支持的业务类型");
            }
        } catch (Exception e) {
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                return Response.fail(be.getErrMsg(), be.getErrCode());
            }
            logger.error("", e);
            return Response.fail("支付发起失败！");
        }

        return Response.fail("操作失败");
    }

    private Response processOpenVip(Request request, String busiType) {
        Long userId = request.getLong("userId");
        String payWay = PayOrder.PAY_QUICK;

        SimpleLock simpleLock = simpleLockFactory.getLock("USER_" + userId);

        try {
            simpleLock.acquire();
            User user = userService.getById(userId);

            if (user.isVip()) {
                return Response.fail("您已经是VIP会员");
            }

            // 随机订单号
            String outTradeNo = PayKit.generateStr();
            String payAmount = sysParamService.findByCode(SysParam.USER_OPEN_VIP_FEE).getParamValue();

            //  调起第三方支付
            UserQuickSign userQuickSign = quickPayService.getUserQuickSignByUserId(userId);
            if (null == userQuickSign) {
                BizUtil.exception("您还未签约快捷支付");
            }

            PayOrder order = payService.createPayOrder(userId, Integer.parseInt(payAmount), PayOrder.PAY_USER_VIP,
                    outTradeNo, payWay, null);

            BigDecimal authAmount = new BigDecimal(payAmount).divide(new BigDecimal(100)).setScale(2);
            Tf56PayQuickPayDataVo dataVo = tf56PayQuickPay("开通VIP", authAmount.toString(),
                    userQuickSign.getCertCode(), outTradeNo, userId, "价格" + authAmount.toString(), busiType);

            payService.updatePayStatus(order, PayOrder.STATUS_PAYING);
            Map result = new HashMap();
            result.put("orderNo", outTradeNo);
            return Response.success().put("data", result);
        } catch (Exception e) {
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                return Response.fail(be.getErrMsg(), be.getErrCode());
            }

            logger.error("", e);
            return Response.fail("支付发起失败");
        } finally {
            try {
                simpleLock.release();
            } catch (Exception e) {
                logger.error("", e);
            }
        }
    }

    private void putPayParam(Long userId, String orderNo, String busiNo, String goodsName, String ggodsDesc,
                             BigDecimal amount, String certCode, String busiType){
        QuickPayVo vo = new QuickPayVo();
        vo.setUserId(userId);
        vo.setOrderNo(orderNo);
        vo.setBusiNo(busiNo);
        vo.setGoodsName(goodsName);
        vo.setGoodsDesc(ggodsDesc);
        vo.setAmount(amount);
        vo.setCertCode(certCode);
        vo.setBusiType(busiType);
        simpleCache.put("TF56PAYQUICKPAY_" + userId, JSON.toJSONString(vo));
    }

    private Response processBuyGzCoin(Request request, String busiType) {

        String extendData = request.getString("extendData");
        JSONObject jsonObject = JSON.parseObject(extendData);

        Long userId = request.getLong("userId");
        //String payWay = jsonObject.getString("payWay");
        String payWay = PayOrder.PAY_QUICK;

        String type = jsonObject.getString("type");


        Integer amount = null;
        BigDecimal fCoinNum = null;

        User user = userService.getById(userId);
        if (!isNewUser(user)) {
            return Response.fail("此功能暂不支持老会员使用！");
        }

        if ("1".equals(type)) {
            // 指定金额，走系统参数
            Long rgId = jsonObject.getLong("rgId");
            RnbExchangeGzDef def = acctService.findRnbBuyGzDef(rgId);
            if (def == null) {
                return Response.fail("参数异常");
            }
            amount = def.getRnb()
                    .multiply(BigDecimal.valueOf(100))
                    .intValue();

            fCoinNum = def.getGzCoin().setScale(2);

        } else {
            if (StringUtil.isEmpty(jsonObject.getString("num"))) {
                return Response.fail("必须输入购买数量");
            }

            // 其他金额
            BigDecimal bigNnum = new BigDecimal(jsonObject.getString("num"));
            if (!NumberUtil.isWholeNumber(bigNnum)) {
                return Response.fail("购买数量必须是整数");
            }

            if (null == user || !user.isNormal()) {
                return Response.fail("用户状态不正确");
            }

            int limitNum = Integer.parseInt(sysParamDao.findByCode(SysParam.BUY_GZ_COIN_MIN_NUM).getParamValue());
            if (bigNnum.intValue() < limitNum) {
                return Response.fail("购买数量不能小于" + limitNum);
            }

            BigDecimal rate = new BigDecimal(sysParamDao.findByCode(SysParam.RNB_GZ_RATE).getParamValue());
            amount = bigNnum
                    .multiply(rate)
                    .multiply(BigDecimal.valueOf(100))
                    .intValue();

            fCoinNum = bigNnum.setScale(2);
        }

        // 随机订单号
        String outTradeNo = PayKit.generateStr();
        try {
            acctService.saveRnbExchangeCoinLog(userId, new BigDecimal(amount), AcctType.ACCT_TYPE_G,
                    fCoinNum, outTradeNo, RnbExchangeCoinLog.STATUS_INIT, request.getString("expend"));

            //  调起第三方支付
            UserQuickSign userQuickSign = quickPayService.getUserQuickSignByUserId(userId);
            if (null == userQuickSign) {
                BizUtil.exception("您还未签约快捷支付");
            }

            // 生成订单
            PayOrder order = payService.createPayOrder(userId, amount, PayOrder.PAY_BUSI_BUY_GZ_COIN, outTradeNo, payWay, fCoinNum);

            Tf56PayQuickPayDataVo dataVo = tf56PayQuickPay("果子购买",  new BigDecimal(amount).divide(new BigDecimal(100)).setScale(2).toString(),
                    userQuickSign.getCertCode(), outTradeNo, userId, "果子购买，数量" + fCoinNum, busiType);

            payService.updatePayStatus(order, PayOrder.STATUS_PAYING);
            Map map = new HashMap();
            map.put("orderNo", outTradeNo);
            return Response.success().put("data", map);
        } catch (Exception e) {
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                return Response.fail(be.getErrMsg(), be.getErrCode());
            }

            logger.error("", e);
            return Response.fail("支付发起失败");
        }
    }

    private boolean isNewUser(User user) {
        //判断是否新用户
        Date limitDate = TimeUtil.parse(this.limitDateStr, "yyyy-MM-dd HH:mm:ss");
        if (null != limitDate && null != user.getCreateTime() && user.getCreateTime().before(limitDate)) {
            return false;
        }
        return true;
    }

    private Response processBuyFCoin(Request request, String busiType) {


        String extendData = request.getString("extendData");
        JSONObject jsonObject = JSON.parseObject(extendData);

        Long userId = request.getLong("userId");
//        String payWay = jsonObject.getString("payWay");
        String payWay = PayOrder.PAY_QUICK;
        String type = jsonObject.getString("type");

        Integer amount = null;
        BigDecimal fCoinNum = null;
        if ("1".equals(type)) {
            // 指定金额，走系统参数
            Long rfId = jsonObject.getLong("rfId");
            RnbExchangeFDef def = acctService.findRnbBuyFDef(rfId);
            if (def == null) {
                return Response.fail("参数异常");
            }
            amount = def.getRnb()
                    .multiply(BigDecimal.valueOf(100))
                    .intValue();

            fCoinNum = def.getFCoin().setScale(2);

        } else {
            if (StringUtil.isEmpty(jsonObject.getString("num"))) {
                return Response.fail("必须输入购买数量");
            }

            // 其他金额
            BigDecimal bigNnum = new BigDecimal(jsonObject.getString("num"));
            if (!NumberUtil.isWholeNumber(bigNnum)) {
                return Response.fail("购买数量必须是整数");
            }

            int limitNum = Integer.parseInt(sysParamDao.findByCode(SysParam.BUY_F_COIN_MIN_NUM).getParamValue());
            if (bigNnum.intValue() < limitNum) {
                return Response.fail("购买数量不能小于" + limitNum);
            }

            BigDecimal rate = new BigDecimal(sysParamDao.findByCode(Const.RNB_F_RATE).getParamValue());
            amount = bigNnum
                    .multiply(rate)
                    .multiply(BigDecimal.valueOf(100))
                    .intValue();

            fCoinNum = bigNnum.setScale(2);
        }

        // 随机订单号
        String outTradeNo = PayKit.generateStr();
        try {
            acctService.saveRnbExchangeCoinLog(userId, new BigDecimal(amount), AcctType.ACCT_TYPE_F,
                    fCoinNum, outTradeNo, RnbExchangeCoinLog.STATUS_INIT, jsonObject.getString("expend"));

            //  调起第三方支付
            UserQuickSign userQuickSign = quickPayService.getUserQuickSignByUserId(userId);
            if (null == userQuickSign) {
                BizUtil.exception("您还未签约快捷支付");
            }

            // 生成订单
            PayOrder order = payService.createPayOrder(userId, amount, PayOrder.PAY_BUSI_BUY_F_COIN, outTradeNo, payWay, fCoinNum);

            Tf56PayQuickPayDataVo dataVo = tf56PayQuickPay("购买福币", new BigDecimal(amount).divide(new BigDecimal(100)).setScale(2).toString(),
                    userQuickSign.getCertCode(), outTradeNo, userId, "购买福币，数量" + fCoinNum, busiType);

            payService.updatePayStatus(order, PayOrder.STATUS_PAYING);
            Map map = new HashMap();
            map.put("orderNo", outTradeNo);
            return Response.success().put("data", map);
        } catch (Exception e) {
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                return Response.fail(be.getErrMsg(), be.getErrCode());
            }

            logger.error("", e);
            return Response.fail("支付发起失败");
        }
    }

    private Response processReal(Request request, String busiType) {
        Long userId = request.getLong("userId");

        SimpleLock simpleLock = simpleLockFactory.getLock("USER_" + userId);

        try {
            simpleLock.acquire();
            User user = userService.getById(userId);
            if (user.isPayAuth()) {
                BizUtil.exception("支付认证已通过，无需认证");
            }

            if (!user.isFace()) {
                BizUtil.exception("人脸信息未认证，请先认证人脸");
            }

            // 随机订单号
            String outTradeNo = PayKit.generateStr();
            String payAmount = sysParamService.findByCode("AUTH_FEE").getParamValue();

            //  调起第三方支付
            BigDecimal authAmount = new BigDecimal(payAmount).divide(new BigDecimal(100)).setScale(2);
            UserQuickSign userQuickSign = quickPayService.getUserQuickSignByUserId(userId);
            if (null == userQuickSign) {
                BizUtil.exception("您还未签约快捷支付");
            }

            PayOrder order = payService.createPayOrder(userId, Integer.parseInt(payAmount), PayOrder.PAY_USER_AUTH,
                    outTradeNo, PayOrder.PAY_QUICK, null);

            Tf56PayQuickPayDataVo dataVo = tf56PayQuickPay("人脸认证费用", authAmount.toString(),
                    userQuickSign.getCertCode(), outTradeNo, userId, "费用：" + authAmount.toString(), busiType);

            payService.updatePayStatus(order, PayOrder.STATUS_PAYING);

            Map result = new HashMap();
            result.put("orderNo", order.getOutTradeNo());

            return Response.success().put("data", result);
        } catch (Exception e) {
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                return Response.fail(be.getErrMsg(), be.getErrCode());
            }

            logger.error("", e);
            return Response.fail("支付发起失败");
        }
    }

    private Tf56PayQuickPayDataVo tf56PayQuickPay(String goodsName, String amount, String certCode, String orderNo, Long userId, String description, String busiType){
        Map<String, Object> param = new HashMap<>();
        param.put("goodsName", goodsName);
        param.put("amount", amount);
        param.put("certCode", certCode);
        param.put("orderNo", orderNo);
        param.put("userId", userId);
        param.put("description", description);

        Tf56PayQuickPayVo vo = null;
        try {
            vo = tpsClient.tf56PayQuickPay(goodsName, amount, certCode, orderNo, userId, description);
            if (null == vo){
                BizUtil.exception("返回对象为空！");
            }
        } catch (Exception e){
            if (e instanceof BizException) {
                BizException be = (BizException) e;
                saveQuickRequestLog(userId, orderNo, "", String.valueOf(be.getErrCode()), be.getErrMsg(), param, vo);
            } else {
                saveQuickRequestLog(userId, orderNo, "", "-99", e.getMessage(), param, vo);
            }
            BizUtil.exception("快捷支付失败！");
        }
        if (!(isSuccess(vo))) {
            logger.error(">>>>" + vo);
            saveQuickRequestLog(userId, orderNo, "", getErrorCode(vo), getErrorMsg(vo), param, vo);
            //如果业务不成功，则返回第三方的错误信息
            if (!"GPBIZ_00".equals(vo.getBiz_code())) {
                BizUtil.exception(vo.getBiz_msg());
            }

            BizUtil.exception("快捷支付失败！");
        }

        Tf56PayQuickPayDataVo dataVo = vo.getDataVo();
        if (null == dataVo) {
            saveQuickRequestLog(userId, orderNo, dataVo.getBusinessrecordnumber(), "-1", "数据对象为空", param, vo);
            BizUtil.exception("快捷支付失败！");
        }

        putPayParam(userId, orderNo, dataVo.getBusinessrecordnumber(), goodsName, description, new BigDecimal(amount), certCode, busiType);

        saveQuickRequestLog(userId, orderNo, dataVo.getBusinessrecordnumber(), getErrorCode(vo), getErrorMsg(vo), param, vo);
        return dataVo;
    }

    private void saveQuickRequestLog(Long userId, String orderNo, String busiNo, String errorCode, String errorMsg, Map reqParam, Tf56PayQuickPayVo vo) {
        if (errorMsg != null && errorMsg.length() > 200) {
            errorMsg = errorMsg.substring(0, 200);
        }
        quickPayService.saveQuickRequestLog(userId, orderNo, busiNo, QuickRequestLog.TYPE_PAY, errorCode, errorMsg, JSON.toJSONString(reqParam), JSON.toJSONString(vo));
    }

    private boolean isSuccess(Tf56PayQuickPayVo vo) {
        return "GP_00".equals(vo.getCode()) && "GPBIZ_00".equals(vo.getBiz_code());
    }


    private String getErrorCode(Tf56PayQuickPayVo vo) {
        if (!"GP_00".equals(vo.getCode())) {
            return vo.getCode();
        }
        if (!"GPBIZ_00".equals(vo.getBiz_code())) {
            return vo.getBiz_code();
        }

        return "0";
    }

    private String getErrorMsg(Tf56PayQuickPayVo vo) {
        if (!"GP_00".equals(vo.getCode())) {
            return vo.getMsg();
        }
        if (!"GPBIZ_00".equals(vo.getBiz_code())) {
            return vo.getBiz_msg();
        }

        return "success";
    }
}